package com.lookoutthebush.companyindex.util;

import com.lookoutthebush.companyindex.domain.BaseDO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * AppointmentLogDO
 *
 * @author xzd
 * @version v1.0
 * @since 2019/10/27
 */
@Component
@Slf4j
public class MyJdbcDAO {

    @Resource
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    private <T extends BaseDO> String getCreateSql(T object) {
        Class<? extends BaseDO> doClass = object.getClass();
        String className = doClass.getSimpleName().toLowerCase();
        String tableName = className.substring(0, className.length() - 2);
        Field[] fields = doClass.getDeclaredFields();
        StringBuilder insertSqlK = new StringBuilder("insert into ");
        StringBuilder insertSqlV = new StringBuilder();
        insertSqlK.append(tableName).append("(");
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                if (ObjectUtils.isEmpty(field.get(object))) {
                    continue;
                }
            } catch (IllegalAccessException e) {
                log.info("build create sql getValue failed,filed:{}", field.getName(), e);
            }
            insertSqlK.append(field.getName()).append(",");
            insertSqlV.append(":").append(field.getName()).append(",");
        }
        insertSqlK.append("createtime) value(");
        insertSqlV.append(":createTime)");
        return insertSqlK.append(insertSqlV).toString();
    }

    private <T extends BaseDO> String getQuerySql(Class<T> clazz) {
        String className = clazz.getSimpleName().toLowerCase();
        String tableName = className.substring(0, className.length() - 2);
        return "select * from " + tableName + " where id = :id";
    }

    private <T extends BaseDO> String getUpdateSql(Class<T> clazz) {
        String className = clazz.getSimpleName().toLowerCase();
        String tableName = className.substring(0, className.length() - 2);
        Field[] fields = clazz.getDeclaredFields();
        StringBuilder updateSql = new StringBuilder("update ");
        updateSql.append(tableName).append(" set ");
        for (Field field : fields) {
            updateSql.append(field.getName().toLowerCase()).append(" = :").append(field.getName()).append(",");
        }
        String sql = updateSql.toString();
        sql = sql.substring(0, sql.length() - 1);
        return sql + " where id = :id";
    }

    public <T extends BaseDO> void create(T object) {
        String sql = getCreateSql(object);
        object.setCreateTime(MyDate.nowDateTimeString());
        SqlParameterSource parameter = new BeanPropertySqlParameterSource(object);
        KeyHolder keyHolder = new GeneratedKeyHolder();
        int result = namedParameterJdbcTemplate.update(sql, parameter, keyHolder);
        if (result <= 0) {
            return;
        }
        Number number = keyHolder.getKey();
        if (null == number) {
            return;
        }
        object.setId(number.longValue());
    }

    /**
     * 查询多条记录
     *
     * @param sql sql
     * @param params 参数
     * @param clazz clas
     * @param <T> 泛型
     * @return list
     */
    public <T> List<T> queryList(String sql, Map<String, ?> params, Class<T> clazz) {
        try {
            return namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<>(clazz));
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }

    public <T> PageHelper<T> queryListByPage(String sql, Map<String, Object> params, Class<T> clazz,
            PageHelper<T> page) {
        try {
            String countSql = "select count(1) " + sql.substring(sql.indexOf("from"));
            int total = queryField(countSql, params, Integer.class);
            sql += " limit :start,:size";
            params.put("start", page.getStart());
            params.put("size", page.getPageSize());
            List<T> objects = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<>(clazz));
            page.setTotal(total);
            page.setData(objects);
        } catch (Exception e) {
            log.error("queryListByPage error", e);
        }
        return page;
    }

    public <T extends BaseDO> T queryById(Long id, Class<T> clazz) {
        String sql = getQuerySql(clazz);
        Map<String, Long> params = new HashMap<>();
        params.put("id", id);
        try {
            return namedParameterJdbcTemplate.queryForObject(sql, params, new BeanPropertyRowMapper<>(clazz));
        } catch (Exception e) {
            return null;
        }
    }

    public <T> T queryForObject(String sql, Map<String, ?> params, Class<T> clazz) {
        try {
            return namedParameterJdbcTemplate.queryForObject(sql, params, new BeanPropertyRowMapper<>(clazz));
        } catch (Exception e) {
            return null;
        }
    }

    public <T> T queryField(String sql, Map<String, ?> params, Class<T> clazz) {
        try {
            return namedParameterJdbcTemplate.queryForObject(sql, params, clazz);
        } catch (Exception e) {
            return null;
        }
    }

    public <T extends BaseDO> void update(T object) {
        String sql = getUpdateSql(object.getClass());
        SqlParameterSource parameter = new BeanPropertySqlParameterSource(object);
        namedParameterJdbcTemplate.update(sql, parameter);
    }
}